#!/bin/bash
set -eo pipefail

# 通用后台管理系统部署脚本 v3.0
# 完全适配 /var/www/huyingying.top 项目结构
# 最后更新：2025年8月

# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'

# 配置区 ================================================
PROJECT_NAME="huyingying.top"
PROJECT_ROOT="/var/www/${PROJECT_NAME}"
BACKEND_DIR="${PROJECT_ROOT}/backend"
FRONTEND_DIR="${PROJECT_ROOT}/frontend"
UPLOAD_DIR="${BACKEND_DIR}/BackOffice/BackOffice.Api/wwwroot/uploads"
NGINX_CONF="/etc/nginx/sites-available/${PROJECT_NAME}"
SYSTEMD_SERVICE="/etc/systemd/system/${PROJECT_NAME}.service"
DB_NAME="soft1_admin"
DB_USER="admin_user"
DB_PASSWORD="h13178502607YY"
DOTNET_ENV="Production"
FRONTEND_PORT=3000
BACKEND_PORT=5000

# 日志函数
log() {
    local level=$1
    local message=$2
    local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
    
    case $level in
        "INFO") color=${GREEN} ;;
        "WARN") color=${YELLOW} ;;
        "ERROR") color=${RED} ;;
        "STEP") color=${BLUE} ;;
        *) color=${NC} ;;
    esac
    
    echo -e "${color}[$level]${NC} ${timestamp} - ${message}"
}

# 检查root权限
check_root() {
    if [[ $EUID -ne 0 ]]; then
        log "ERROR" "此脚本必须以root用户运行"
        exit 1
    fi
}

# 验证目录结构
validate_structure() {
    log "STEP" "验证项目结构..."
    
    declare -a required_dirs=(
        "${FRONTEND_DIR}/mini-flow"
        "${BACKEND_DIR}/BackOffice"
        "${UPLOAD_DIR}"
    )
    
    for dir in "${required_dirs[@]}"; do
        if [ ! -d "$dir" ]; then
            log "ERROR" "目录不存在：$dir"
            log "INFO" "当前目录结构："
            tree -L 3 "${PROJECT_ROOT}" || ls -lR "${PROJECT_ROOT}"
            exit 1
        fi
    done
    
    # 特殊文件检查
    if [ ! -f "${FRONTEND_DIR}/mini-flow/package.json" ]; then
        log "ERROR" "前端缺少 package.json"
        log "INFO" "前端目录内容："
        ls -l "${FRONTEND_DIR}/mini-flow"
        exit 1
    fi
    
    if [ ! -f "${BACKEND_DIR}/BackOffice/BackOffice.sln" ]; then
        log "WARN" "后端缺少解决方案文件，尝试自动生成..."
        cd "${BACKEND_DIR}/BackOffice"
        dotnet new sln -n BackOffice
        find . -name "*.csproj" -exec dotnet sln add {} \;
    fi
}

# 部署前端
deploy_frontend() {
    log "STEP" "部署前端应用..."
    
    local source_dir="${FRONTEND_DIR}/mini-flow"
    local target_dir="${FRONTEND_DIR}/dist"
    
    # 严格路径验证
    cd "${source_dir}" || {
        log "ERROR" "无法进入前端目录"
        exit 1
    }
    
    # 清理安装
    log "INFO" "安装前端依赖..."
    rm -rf node_modules
    pnpm install || {
        log "ERROR" "依赖安装失败"
        exit 1
    }
    
    # 构建项目
    log "INFO" "构建生产版本..."
    NODE_OPTIONS="--max-old-space-size=4096" pnpm run build || {
        log "ERROR" "构建失败"
        exit 1
    }
    
    # 部署到目标目录
    mkdir -p "${target_dir}"
    rsync -a --delete "${source_dir}/dist/" "${target_dir}/"
    
    log "INFO" "前端部署完成"
}

# 部署后端
deploy_backend() {
    log "STEP" "部署后端应用..."
    
    local backend_dir="${BACKEND_DIR}/BackOffice"
    local publish_dir="${BACKEND_DIR}/publish"
    
    # 定位API项目（适配Web/Api两种命名）
    local api_project=$(find "${backend_dir}" -type f \( -name "*.Web.csproj" -o -name "*.Api.csproj" \) | head -1)
    if [ -z "$api_project" ]; then
        log "ERROR" "未找到API项目文件"
        find "${backend_dir}" -name "*.csproj" | sed 's/^/ - /'
        exit 1
    fi
    
    # 分层构建
    cd "${backend_dir}"
    dotnet restore
    for layer in Domain Application Infrastructure; do
        find . -name "*.$layer.csproj" -exec dotnet build {} -c Release --no-restore \;
    done
    
    # 发布API项目
    dotnet publish "$api_project" -c Release -o "${publish_dir}" || {
        log "ERROR" "发布失败"
        exit 1
    }
    
    log "INFO" "后端部署完成"
}

# 配置数据库
configure_db() {
    log "STEP" "配置数据库..."
    
    sudo -u postgres psql -c "DO \$\$
    BEGIN
        IF NOT EXISTS (SELECT FROM pg_roles WHERE rolname = '${DB_USER}') THEN
            CREATE ROLE ${DB_USER} WITH LOGIN PASSWORD '${DB_PASSWORD}';
        END IF;
    END
    \$\$;" || true
    
    sudo -u postgres psql -c "CREATE DATABASE ${DB_NAME} WITH OWNER = ${DB_USER};" 2>/dev/null || true
    
    log "INFO" "数据库配置完成"
}

# 配置系统服务
configure_systemd() {
    log "STEP" "配置系统服务..."
    
    local assembly_name=$(basename $(find "${BACKEND_DIR}/publish" -name "*.dll" ! -name "*Views.dll" | head -1) .dll)
    
    cat > "${SYSTEMD_SERVICE}" <<EOF
[Unit]
Description=BackOffice API Service
After=network.target postgresql.service
StartLimitIntervalSec=60

[Service]
Type=simple
User=www-data
Group=www-data
WorkingDirectory=${BACKEND_DIR}/publish
ExecStart=/usr/bin/dotnet ${BACKEND_DIR}/publish/${assembly_name}.dll
Restart=always
RestartSec=10
Environment=ASPNETCORE_ENVIRONMENT=${DOTNET_ENV}
Environment=DOTNET_PRINT_TELEMETRY_MESSAGE=false
Environment=ASPNETCORE_URLS=http://*:${BACKEND_PORT}
SyslogIdentifier=${PROJECT_NAME}
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target
EOF

    systemctl daemon-reload
    systemctl enable "${PROJECT_NAME}"
    
    log "INFO" "系统服务配置完成"
}

# 配置Nginx
configure_nginx() {
    log "STEP" "配置Nginx..."
    
    cat > "${NGINX_CONF}" <<EOF
server {
    listen 80;
    server_name ${PROJECT_NAME};
    
    # 重定向HTTP到HTTPS
    return 301 https://\$server_name\$request_uri;
}

server {
    listen 443 ssl http2;
    server_name ${PROJECT_NAME};
    
    # SSL证书配置（需要替换为你的实际证书路径）
    ssl_certificate /etc/ssl/certs/${PROJECT_NAME}.crt;
    ssl_certificate_key /etc/ssl/private/${PROJECT_NAME}.key;
    
    # SSL配置
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384;
    ssl_prefer_server_ciphers off;
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 10m;
    
    # 前端静态文件
    location / {
        root ${FRONTEND_DIR}/dist;
        try_files \$uri \$uri/ /index.html;
        add_header Cache-Control "no-cache";
    }
    
    # 后端API代理
    location /api/ {
        proxy_pass http://127.0.0.1:${BACKEND_PORT};
        proxy_http_version 1.1;
        proxy_set_header Upgrade \$http_upgrade;
        proxy_set_header Connection keep-alive;
        proxy_set_header Host \$host;
        proxy_set_header X-Real-IP \$remote_addr;
        proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
    }
    
    # 文件上传
    location /uploads/ {
        alias ${UPLOAD_DIR}/;
        client_max_body_size 100M;
        expires 1y;
        add_header Cache-Control "public, immutable";
    }
    
    access_log ${PROJECT_ROOT}/logs/nginx_access.log;
    error_log ${PROJECT_ROOT}/logs/nginx_error.log;
}
EOF

    ln -sf "${NGINX_CONF}" "/etc/nginx/sites-enabled/"
    nginx -t && systemctl restart nginx
    
    log "INFO" "Nginx配置完成"
}

# 设置权限
set_permissions() {
    log "STEP" "设置文件权限..."
    
    chown -R www-data:www-data "${PROJECT_ROOT}"
    find "${PROJECT_ROOT}" -type d -exec chmod 755 {} \;
    find "${PROJECT_ROOT}" -type f -exec chmod 644 {} \;
    
    # 特殊权限
    chmod -R 775 "${UPLOAD_DIR}"
    # 在 deploy.sh 中添加以下代码（例如在 "验证项目结构" 步骤前）
    mkdir -p /var/www/huyingying.top/{logs,uploads,scripts}  # 一次性创建所有缺失目录
    chmod 755 /var/www/huyingying.top/{logs,uploads,scripts}
    
    log "INFO" "权限设置完成"
}

# 显示部署摘要
show_summary() {
    echo -e "\n${GREEN}=== 部署成功 ===${NC}"
    echo -e "项目目录: ${BLUE}${PROJECT_ROOT}${NC}"
    echo -e "前端访问: ${BLUE}https://${PROJECT_NAME}${NC}"
    echo -e "API端点: ${BLUE}https://${PROJECT_NAME}/api/swagger${NC}"
    echo -e "上传目录: ${BLUE}${UPLOAD_DIR}${NC}"
    echo -e "\n${YELLOW}管理命令:${NC}"
    echo -e "  启动服务: systemctl start ${PROJECT_NAME}"
    echo -e "  查看日志: journalctl -u ${PROJECT_NAME} -f"
    echo -e "  重新部署: ${0} install"
    echo -e "\n${GREEN}部署完成时间: $(date)${NC}"
}

# 主部署流程
main() {
    check_root
    validate_structure
    configure_db
    deploy_frontend
    deploy_backend
    configure_systemd
    configure_nginx
    set_permissions
    
    log "STEP" "启动服务..."
    systemctl restart "${PROJECT_NAME}"
    
    show_summary
}

# 执行入口
case "$1" in
    "install")
        main
        ;;
    "update")
        log "INFO" "执行更新部署..."
        deploy_frontend
        deploy_backend
        systemctl restart "${PROJECT_NAME}"
        ;;
    *)
        echo "使用方法: $0 {install|update}"
        exit 1
        ;;
esac